package com.xjrsoft.module.organization.service.impl;

import cn.dev33.satoken.secure.SaSecureUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.dingtalk.api.DefaultDingTalkClient;
import com.dingtalk.api.DingTalkClient;
import com.dingtalk.api.request.OapiV2UserCreateRequest;
import com.dingtalk.api.request.OapiV2UserUpdateRequest;
import com.dingtalk.api.response.OapiV2DepartmentListsubResponse;
import com.dingtalk.api.response.OapiV2UserCreateResponse;
import com.dingtalk.api.response.OapiV2UserListResponse;
import com.dingtalk.api.response.OapiV2UserUpdateResponse;
import com.github.yulichang.toolkit.MPJWrappers;
import com.taobao.api.ApiException;
import com.xjrsoft.common.constant.GlobalConstant;
import com.xjrsoft.common.utils.VoToColumnUtil;
import com.xjrsoft.common.utils.WeChatUtil;
import com.xjrsoft.config.CommonPropertiesConfig;
import com.xjrsoft.module.organization.entity.Department;
import com.xjrsoft.module.organization.entity.User;
import com.xjrsoft.module.organization.entity.UserDeptRelation;
import com.xjrsoft.module.organization.service.DingtalkService;
import com.xjrsoft.module.organization.service.IDepartmentService;
import com.xjrsoft.module.organization.service.IUserDeptRelationService;
import com.xjrsoft.module.organization.service.IUserService;
import com.xjrsoft.module.organization.vo.UserPageVo;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@Service
@AllArgsConstructor
public class DingtalkServiceImpl implements DingtalkService {

    private final IUserService userService;

    private final IUserDeptRelationService userDeptRelationService;

    private final IDepartmentService departmentService;

    private final WeChatUtil weChatUtil;

    private final CommonPropertiesConfig propertiesConfig;

    @Override
    public boolean syncUsersToDingTalk(Long departmentId) {
        Department department = departmentService.getById(departmentId);
        Department settingDept = findSettingDept(department);
        if (department.getDingtalkDeptId() == null) {
            throw new RuntimeException("请先同步部门！");
        }
        List<User> userList = userService.selectJoinList(User.class,
                MPJWrappers.<User>lambdaJoin()
                        .distinct()
                        .eq( UserDeptRelation::getDeptId, departmentId)
                        .select(User::getId)
                        .select(User.class, x -> VoToColumnUtil.fieldsToColumns(UserPageVo.class).contains(x.getProperty()))
                        .leftJoin(UserDeptRelation.class, UserDeptRelation::getUserId, User::getId));
        // 开始同步
        String accessToken  = weChatUtil.getDingTalkToken(settingDept.getDingAppKey(), settingDept.getDingAppSecret());
        for (User user : userList) {
            if (StrUtil.isEmpty(user.getDingtalkUserId())) {
                createUserToDingTalk(department.getDingtalkDeptId(), user, accessToken);
            } else {
                updateUserToDingTalk(user, accessToken);
            }
        }
        return true;
    }

    @Override
    public boolean syncUsersToSystem(Long departmentId) {
        Department department = departmentService.getById(departmentId);
        Department settingDept = findSettingDept(department);
        if (department.getDingtalkDeptId() == null) {
            throw new RuntimeException("请先同步部门！");
        }
        List<OapiV2UserListResponse.ListUserResponse> dingTalkUserList = weChatUtil.getDingTalkUsersOfDepartment(department.getDingtalkDeptId(), settingDept.getDingAppKey(), settingDept.getDingAppSecret());
        if (CollectionUtils.isNotEmpty(dingTalkUserList)) {
            List<String> dingTalkUserIds = dingTalkUserList.stream().map(OapiV2UserListResponse.ListUserResponse::getUserid).collect(Collectors.toList());
            List<User> userList = userService.list(Wrappers.lambdaQuery(User.class).in(User::getDingtalkUserId, dingTalkUserIds));
            List<User> updateUserList = new ArrayList<>(dingTalkUserList.size());
            List<UserDeptRelation> userDeptRelationList = new ArrayList<>(dingTalkUserList.size());
            List<Long> updateUserIdList = new ArrayList<>(dingTalkUserList.size());
            for (OapiV2UserListResponse.ListUserResponse dingTalkUserDto : dingTalkUserList) {
                User updateUser = new User();
                Long userId = null;
                boolean exist = false;
                for (User user : userList) {
                    if (StrUtil.equals(dingTalkUserDto.getUserid(), user.getDingtalkUserId())) {
                        userId = user.getId();
                        exist = true;
                        break;
                    }
                }
                if (!exist) {
                    userId = IdUtil.getSnowflakeNextId();
                    // 默认密码
                    updateUser.setPassword(SaSecureUtil.md5BySalt(propertiesConfig.getDefaultPassword(), GlobalConstant.SECRET_KEY));
                }
                // 构建同步的user信息
                updateUser.setId(userId);
                updateUser.setUserName(dingTalkUserDto.getMobile());
                updateUser.setName(dingTalkUserDto.getName());
                updateUser.setMobile(dingTalkUserDto.getMobile());
                updateUser.setEmail(dingTalkUserDto.getEmail());
                updateUser.setDingtalkUserId(dingTalkUserDto.getUserid());
//                updateUser.setGender(Integer.valueOf(dingTalkUserDto.getGender()));
                updateUserList.add(updateUser);
                // 构建用户部门关系
                UserDeptRelation userDeptRelation = new UserDeptRelation();
                userDeptRelation.setUserId(userId);
                userDeptRelation.setDeptId(departmentId);
                userDeptRelationList.add(userDeptRelation);

                updateUserIdList.add(userId);
            }
            userService.saveOrUpdateBatch(updateUserList);
            // 删除旧的部门用户关联关系
            userDeptRelationService.remove(Wrappers.lambdaQuery(UserDeptRelation.class)
                    .eq(UserDeptRelation::getDeptId, departmentId)
                    .in(UserDeptRelation::getUserId, updateUserIdList));
            userDeptRelationService.saveBatch(userDeptRelationList);
            return true;
        } else {
            throw new RuntimeException("钉钉没有人员！");
        }
    }

    @Override
    public boolean syncDepartments(Long departmentId) {
        Department department = departmentService.getById(departmentId);
        if (department.getDingtalkDeptId() == null) {
            throw new RuntimeException("部门“" + department.getName() + "”尚未同步！");
        }
        Department settingDept = findSettingDept(department);
        List<OapiV2DepartmentListsubResponse.DeptBaseResponse> dingTalkDeptList = weChatUtil.getDingTalkDepartmentList(
                settingDept.getDingAppKey(), settingDept.getDingAppSecret(), department.getDingtalkDeptId());
        if (CollectionUtils.isNotEmpty(dingTalkDeptList)) {
            List<Long> dingTalkDeptIdList = dingTalkDeptList.stream().map(OapiV2DepartmentListsubResponse.DeptBaseResponse::getDeptId).collect(Collectors.toList());
            List<Department> departmentList = departmentService.list(Wrappers.lambdaQuery(Department.class)
                    .select(Department::getId, Department::getDingtalkDeptId)
                    .in(Department::getDingtalkDeptId, dingTalkDeptIdList));
            // id映射，key：企业微信部门id，value：系统部门id
            Map<Long, Long> idMap = new HashMap<>(dingTalkDeptIdList.size());
            List<Department> updateDepartmentList = new ArrayList<>(dingTalkDeptList.size());
            for (OapiV2DepartmentListsubResponse.DeptBaseResponse dingTalkDepartDto : dingTalkDeptList) {
                boolean exist = false;
                Long deptId = null;
                Department updateDepartment = new Department();
                for (Department sysDept : departmentList) {
                    if (dingTalkDepartDto.getDeptId().equals(sysDept.getDingtalkDeptId())) {
                        deptId = sysDept.getId();
                        exist = true;
                        break;
                    }
                }
                if (!exist) {
                    deptId = IdUtil.getSnowflakeNextId();
                }
                updateDepartment.setName(dingTalkDepartDto.getName());
//                updateDepartment.setCode(dingTalkDepartDto.getName_en());
                updateDepartment.setId(deptId);
                updateDepartment.setDingtalkDeptId(dingTalkDepartDto.getDeptId());
                updateDepartment.setParentId(dingTalkDepartDto.getParentId());
                updateDepartmentList.add(updateDepartment);
                idMap.put(dingTalkDepartDto.getDeptId(), deptId);
            }
            // 处理上级部门
            for (Department updateDepartment : updateDepartmentList) {
                Long parentId = idMap.get(updateDepartment.getParentId());
                updateDepartment.setParentId(parentId == null ? departmentId : parentId);
            }
            return departmentService.saveOrUpdateBatch(updateDepartmentList);
        }
        return true;
    }

    public boolean updateUserToDingTalk(User user, String accessToken) {
        DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/user/update");
        OapiV2UserUpdateRequest req = new OapiV2UserUpdateRequest();
        req.setUserid(user.getDingtalkUserId());
        req.setName(user.getName());
        req.setHideMobile(false);
        req.setTitle(user.getNickName());
        req.setEmail(user.getEmail());
        req.setRemark(user.getRemark());
        req.setDeptIdList("2,3,4");
        req.setMobile(user.getMobile());
        req.setLanguage("zh_CN");
        OapiV2UserUpdateResponse rsp = null;
        try {
            rsp = client.execute(req, accessToken);
        } catch (ApiException e) {
            log.error("同步钉钉用户出错！用户名：" + user.getNickName(), e);
           return false;
        }
        return rsp.getErrcode() == 0L;
    }

    public boolean createUserToDingTalk(Long dingDeptId, User user, String accessToken) {
        DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/user/create");
        OapiV2UserCreateRequest req = new OapiV2UserCreateRequest();
        req.setUserid(user.getUserName());
        req.setName(user.getName());
        req.setMobile(user.getMobile());
        req.setTitle(user.getNickName());
        req.setEmail(user.getEmail());
        req.setRemark(user.getRemark());
        req.setDeptIdList(dingDeptId.toString());
        OapiV2UserCreateResponse rsp = null;
        try {
            rsp = client.execute(req, accessToken);
        } catch (ApiException e) {
            log.error("同步钉钉用户出错！用户名：" + user.getNickName(), e);
            return false;
        }
        return rsp.getErrcode() == 0L;
    }

    private Department findSettingDept(Department department) {
        if (department == null) {
            throw new RuntimeException("请配置部门的钉钉配置");
        } else if (StrUtil.isEmpty(department.getDingAppKey()) || StrUtil.isEmpty(department.getDingAppSecret())) {
            Department parent = departmentService.getById(department.getParentId());
            department = findSettingDept(parent);
        }
        return department;
    }
}
